import re
import os
from SecondaryMarket import settings
from rest_framework.views import APIView
from rest_framework.generics import ListAPIView, CreateAPIView, DestroyAPIView, UpdateAPIView
from django.core.cache import cache
from django.db import transaction
from utils.encryption import sha256, create_token, creat_verification_code
from utils.response import validData, Error, Success
from utils.weChatApi import get_openid
from utils.EmailSender import SendEmail
from utils.serializer import RegisterSerializer, UserInfoSerializer, GoodSerializer, WantedUserSerializer
from utils.pagination import GoodsPagination
from utils.functions import image_delete
from .models import UserInfo, Image, WeChatCertification, Tags, Goods, GoodsAllImage


# Create your views here.

# TODO 添加数据库回滚
class Register(APIView):
    """
    注册接口
    """
    authentication_classes = []

    @validData(Error(400, "访问失败"), Success(200, "访问成功"))
    def post(self, request, *args, **kwargs):
        # 将数据放入字典
        user_data = dict()
        user_data["user_name"] = request.data["user_name"]
        user_data["student_id"] = request.data["student_id"]
        user_data["password"] = sha256(request.data["password"])
        user_data["qq"] = request.data["qq"]
        user_data["school_zone"] = request.data["school_zone"]
        user_data["profile"] = request.data["profile"]
        avatar = request.data["avatar"]
        # 判断用户是否已注册
        obj = UserInfo.objects.filter(student_id=user_data["student_id"], user_name=user_data["user_name"],
                                      password=user_data["password"])
        assert not obj, "用户已注册"
        ser = RegisterSerializer(data=request.data)
        if ser.is_valid():
            # 数据通过验证
            # 创建图片对象
            user_data["avatar"] = Image.objects.create(images=avatar)
            UserInfo.objects.create(**user_data)
            return
        else:
            raise Exception(ser.errors)


class WeChatRegister(APIView):
    """
    微信注册接口
    """
    authentication_classes = []

    @validData(Error(400, "访问失败"), Success(200, "访问成功"))
    def post(self, request, *args, **kwargs):
        # 将数据放入字典
        user_data = dict()
        user_data["user_name"] = request.data["user_name"]
        user_data["student_id"] = request.data["student_id"]
        user_data["password"] = sha256(request.data["password"])
        user_data["qq"] = request.data["qq"]
        user_data["school_zone"] = request.data["school_zone"]
        user_data["profile"] = request.data["profile"]
        avatar = request.data["avatar"]
        js_code = request.data["js_code"]
        openid = get_openid(js_code)["openid"]
        # openid = "123456"
        # 判断用户是否已注册
        obj = UserInfo.objects.filter(student_id=user_data["student_id"], user_name=user_data["user_name"],
                                      password=user_data["password"])
        assert not obj, "用户已注册"
        ser = RegisterSerializer(data=request.data)
        if ser.is_valid():
            # 数据通过验证
            # 创建图片对象
            user_data["avatar"] = Image.objects.create(images=avatar)
            user = UserInfo.objects.create(**user_data)
            WeChatCertification.objects.create(user=user, openid=openid)
            return {"open_id": openid, "avatar": user_data["avatar"].photo_url()}
        else:
            raise Exception(ser.errors)


class Login(APIView):
    """
    用户名， 密码登录接口
    """
    authentication_classes = []

    @validData(Error(400, "访问失败"), Success(200, "访问成功"))
    def get(self, request, *args, **kwargs):
        user_data = dict()
        user_data["user_name"] = request.query_params["user_name"]
        user_data["password"] = sha256(request.query_params["password"])
        user_obj = UserInfo.objects.filter(**user_data).first()
        assert user_obj, "用户名或密码错误"
        request._request.session['user'] = {"pk": user_obj.pk}
        print(request._request.session['user'])
        ser = UserInfoSerializer(instance=user_obj, many=False)
        return ser.data


class WeChatLogin(APIView):
    """
    微信登录接口
    """
    authentication_classes = []

    @validData(Error(400, "访问失败"), Success(200, "访问成功"))
    def get(self, request, *args, **kwargs):
        # 确定用户的openid
        js_code = request.query_params["js_code"]
        openid = get_openid(js_code)["openid"]
        # openid = "123456"
        obj = WeChatCertification.objects.filter(openid=openid).first()
        assert obj, "用户登录失败"
        # openid存在于数据库中
        user_obj = obj.user
        # 生成session
        request._request.session['user'] = {"pk": user_obj.pk}
        ser = UserInfoSerializer(instance=user_obj, many=False)
        return ser.data


class AvatarModify(APIView):
    """
    头像修改接口
    """

    @validData(Error(400, "访问失败"), Success(200, "访问成功"))
    def patch(self, request, *args, **kwargs):
        # 将数据放入字典
        user_data = dict()
        avatar = request.data["avatar"]
        user_obj = request.user
        assert user_obj, "用户不存在"
        try:
            user_data["avatar"] = Image.objects.filter(userinfo=user_obj).first()
            # 将原来的图片删除
            image_delete(instance=user_data["avatar"])
            # 更新头像
            user_data["avatar"].images = avatar
            user_data["avatar"].save()
            return {"avatar": user_data["avatar"].photo_url()}
        except Exception as e:
            raise Exception("更新失败")


# TODO 修改用户信息时对信息进行验证
class UserInfoModify(APIView):
    """
    个人信息修改接口（头像，密码，qq除外）
    """

    @validData(Error(400, "访问失败"), Success(200, "访问成功"))
    def patch(self, request, *args, **kwargs):
        user_obj = request.user
        assert user_obj, "用户不存在"
        # 将数据放入字典
        user_data = dict()
        user_data["password"] = request.data["password"]
        assert user_obj.password == sha256(user_data["password"]), "密码错误"
        user_data["user_name"] = request.data["user_name"]
        user_data["student_id"] = request.data["student_id"]
        user_data["school_zone"] = request.data["school_zone"]
        user_data["profile"] = request.data["profile"]
        user_data["qq"] = user_obj.qq
        ser = RegisterSerializer(data=user_data)
        if ser.is_valid():
            try:
                user_obj.student_id = user_data["student_id"]
                user_obj.user_name = user_data["user_name"]
                user_obj.school_zone = user_data["school_zone"]
                user_obj.profile = user_data["profile"]
                user_obj.save()
                user_ser = UserInfoSerializer(instance=user_obj, many=False)
                return user_ser.data
            except Exception as e:
                raise Exception("更新失败")
        else:
            return ser.errors


class GetCode(APIView):
    """
    获取验证码
    """

    @validData(Error(400, "访问失败"), Success(200, "访问成功"))
    def get(self, request, *args, **kwargs):
        user_obj = request.user
        print(user_obj)
        # 生成验证码存储到Redis并设置有效期# 使用配置的redis数据库的别名，创建连接到redis的对象
        verification_code = creat_verification_code()
        cache.set(user_obj.pk, verification_code, 300)  # 该值的有效期为300s
        # 发送验证码
        qq = user_obj.qq
        email_sender = SendEmail(email_name="小黑市")
        email_sender.send(
            receiver_list=[user_obj.qq + "@qq.com", ],
            email_text="【小黑市】您的验证码为" + verification_code + "(5分钟有效，如非本人操作，请忽略。)",
            receiver_name=user_obj.user_name
        )
        # 记得退出
        email_sender.quit()
        return


# 测试接口
class Test(APIView):
    authentication_classes = []

    @transaction.atomic()
    @validData(Error(400, "访问失败"), Success(200, "访问成功"))
    def get(self, request, *args, **kwargs):
        user_data = dict()
        return


class PasswordModify(APIView):
    """
    密码修改接口
    """

    @validData(Error(400, "访问失败"), Success(200, "访问成功"))
    def patch(self, request, *args, **kwargs):
        user_data = dict()
        user_data["password"] = request.data["password"]
        # 验证密码格式
        # 密码最少6位，包括至少1个大写字母，1个小写字母，1个数字，1个特殊字符
        pattern = re.compile(r"^.*(?=.{6,})(?=.*\d)(?=.*[A-Z])(?=.*[a-z])(?=.*[~!@#$%^&*? ]).*$"r"")
        if pattern.match(user_data["password"]):
            ver_code = request.data["ver_code"]
            user_obj = request.user
            # 判断Redis中是否存在
            assert ver_code == cache.get(user_obj.pk), "验证码无效"
            try:
                user_obj.password = sha256(user_data["password"])
                user_obj.save()
            except Exception as e:
                raise Exception("密码修改失败")
            return
        else:
            raise Exception("密码错误")


class QQModify(APIView):
    """
    qq修改接口
    """

    @validData(Error(400, "访问失败"), Success(200, "访问成功"))
    def patch(self, request, *args, **kwargs):
        user_data = dict()
        user_data["qq"] = request.data["qq"]
        # 验证qq格式
        pattern = re.compile(r"^[1-9][0-9]{4,}$")
        if pattern.match(user_data["qq"]):
            ver_code = request.data["ver_code"]
            user_obj = request.user
            # 判断Redis中是否存在
            assert ver_code == cache.get(user_obj.pk), "验证码无效"
            try:
                user_obj.qq = user_data["qq"]
                user_obj.save()
                ser = UserInfoSerializer(instance=user_obj, many=False)
                return ser.data
            except Exception as e:
                Exception("qq修改失败")
            return
        else:
            raise Exception("qq格式错误")


# TODO 开发用户注销接口
class Logout(APIView):
    """
    用户注销接口
    """

    @validData(Error(400, "访问失败"), Success(200, "访问成功"))
    def delete(self, request, *args, **kwargs):
        user_obj = request.user
        user_obj.delete()
        return


class Exit(APIView):
    """
    退出登录接口
    """

    @validData(Error(400, "访问失败"), Success(200, "访问成功"))
    def get(self, request, *args, **kwargs):
        ser = UserInfoSerializer(instance=request.user, many=False)
        request.session.flush()
        return ser.data


class GoodUpload(APIView):
    """
    商品上传接口
    """

    @validData(Error(400, "访问失败"), Success(200, "访问成功"))
    def post(self, request, *args, **kwargs):
        try:
            good_data = dict()
            good_data["seller"] = request.data["user_id"]
            good_data["seller"] = UserInfo.objects.filter(id=good_data["seller"]).first()
            assert good_data["seller"], "找不到用户"
            good_data["goods_main_image"] = request.data["goods_main_image"]
            good_data["goods_title"] = request.data["goods_title"]
            good_data["goods_price"] = request.data["goods_price"]
            good_data["goods_desc"] = request.data["goods_desc"]
            good = Goods.objects.create(**good_data)
            goods_img = request.data["goods_img"]
            # 保存商品图片，并与商品建立关联
            for img in goods_img:
                GoodsAllImage.objects.create(image_path=img, product=good)
            # 商品标签与商品建立关联
            goods_tags = request.data["goods_tags"]
            tags = list()
            for tag in goods_tags:
                tags.append(Tags.objects.update_or_create(tags_content=tag, defaults={"tags_content": tag})[0].pk)
            good.goods_tags.add(*tags)
        except Exception as e:
            # raise e
            raise Exception("商品添加失败")
        ser = GoodSerializer(instance=good, many=False)
        return ser.data


class GetUserInfo(ListAPIView):
    """
    获取用户信息接口
    """
    serializer_class = UserInfoSerializer
    authentication_classes = []

    def get_queryset(self):
        id = self.request.query_params["user_id"]
        user_obj = UserInfo.objects.filter(id=id)
        return user_obj


class GetGoods(ListAPIView):
    """
    获取某一用户售买的商品
    """
    pagination_class = GoodsPagination
    serializer_class = GoodSerializer

    def get_queryset(self):
        user_id = self.request.query_params["user_id"]
        goods = Goods.objects.filter(seller=user_id)
        return goods


"""
write by Titto
"""

class WantedUser(ListAPIView):

    serializer_class = WantedUserSerializer
    def get_queryset(self):
        '''
        获取 [想要此商品的用户]

        根据商品 id 获取 [想要此商品的用户]
        '''
        goods_id = self.request.get('goods_id')
        return Goods.objects.filter(pk=goods_id)

    def is_valid(self, data):
        '''
        判断是否 商品 以及 用户 存在，

        并返回处理后的 instance
        '''
        goods_id = data.get('goods_id')
        wanted_user_id = data.get('user_id')

        goods_obj = Goods.objects.filter(pk=goods_id).first()
        assert goods_obj is not None, "不存在此商品"

        wanted_user_obj = UserInfo.objects.filter(pk=wanted_user_id).first()
        assert wanted_user_obj is not None, "不存在此用户"

        return goods_obj, wanted_user_obj

    @validData(Error(400, "访问失败"), Success(200, "访问成功"))
    def patch(self, request, *args, **kwargs):
        '''
        更新 [想要此商品的用户]

        根据商品 id 和 用户的 id
        将此用户添加到[想要此商品的用户]中
        '''
        goods_obj, wanted_user_obj = self.is_valid(request.data)
        goods_obj.goods_wanted_person.add(wanted_user_obj)

    @validData(Error(400, "访问失败"), Success(200, "访问成功"))
    def delete(self, request, *args, **kwargs):
        '''
        删除 [不想要此商品的用户]

        根据商品 id 和 用户的 id
        将此用户从[想要此商品的用户]中移除
        '''
        goods_obj, not_wanted_user_obj = self.is_valid(request.data)
        # 保留副本
        wanted_user_list = goods_obj.goods_wanted_person.all()
        # 清空
        goods_obj.goods_wanted_person.clear()
        # 重新添加
        for user in wanted_user_list:
            if user == not_wanted_user_obj: continue
            goods_obj.goods_wanted_person.add(user)

class GoodsSearch(ListAPIView):
    """
    根据搜索内容获取所需商品
    """
    serializer_class = GoodSerializer
    pagination_class = GoodsPagination
    def get_queryset(self):
        search_words = self.request.query_params["search_words"]
        goods = Goods.objects.filter(goods_title__contains=search_words)
        return goods










class GoodsModify(APIView):
    """
    修改商品信息
    """

    @validData(Error(400, "访问失败"), Success(200, "访问成功"))
    def patch(self, request, *args, **kwargs):
        try:
            id = request.data["id"]
            good = Goods.objects.filter(id=id).first()
            assert good.seller.id == request.user.pk, "没有修改权限"
            good.goods_title = request.data["goods_title"]
            good.goods_price = request.data["goods_price"]
            good.goods_main_image = request.data["goods_main_image"]
            good.goods_title = request.data["goods_title"]
            good.goods_price = request.data["goods_price"]
            good.goods_desc = request.data["goods_desc"]
            # 删除原有图片
            images = GoodsAllImage.objects.filter(product=id)
            for image in images:
                name = image.image_path.split("/")[-1:]
                # url = settings.STATICFILES_DIRS[0] + "/" + name[0]
                # os.remove(path=url)
                image.delete()
            # 添加新图片
            goods_img = request.data["goods_img"]
            # 保存商品图片，并与商品建立关联
            for img in goods_img:
                GoodsAllImage.objects.create(image_path=img, product=good)
            # 商品标签与商品建立关联
            new_tags = request.data["goods_tags"]
            tags = list()
            # 取出商品原有标签
            goods_tags = good.goods_tags.all()
            print(goods_tags)
            # 删除原有标签
            for tag in goods_tags:
                tag.delete()
            # 添加新标签
            for tag in new_tags:
                tags.append(Tags.objects.update_or_create(tags_content=tag, defaults={"tags_content": tag})[0].pk)
            # 商品与新标签建立关联
            good.goods_tags.add(*tags)
            # 保存商品
            good.save()
            ser = GoodSerializer(good, many=False)
            return ser.data
        except:
            raise Exception("商品信息修改失败")
